package org.apache.ocean;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.lucene.search.Query;
import org.jdom.Element;

/**
 * 
 * @author jasonr
 */
public class FacetResponse {
	public List<FieldFacet> fieldFacets = new ArrayList<FieldFacet>();
	public List<QueryFacet> queryFacets = new ArrayList<QueryFacet>();

	public FacetResponse() {
	}

	public FacetResponse(Element root) throws Exception {
		for (Element queryFacetElement : XMLUtil.getChildren("queryfacet", root)) {
			queryFacets.add(new QueryFacet(queryFacetElement));
		}
		for (Element fieldFacetElement : XMLUtil.getChildren("fieldfacet", root)) {
			fieldFacets.add(new FieldFacet(fieldFacetElement));
		}
	}

	public Element toElement(IndexSchema indexSchema) throws Exception {
		Element root = new Element("facetresponse");
		if (queryFacets != null) {
			for (QueryFacet queryFacet : queryFacets) {
				root.addContent(queryFacet.toElement());
			}
		}
		if (fieldFacets != null) {
			for (FieldFacet fieldFacet : fieldFacets) {
				root.addContent(fieldFacet.toElement(indexSchema));
			}
		}
		return root;
	}

	public static class QueryFacet implements CElement {
		public String id;
		@XML(exclude=true)
		public Query query;
		public String queryString;
		public AtomicLong count;

		public QueryFacet() {
		}
    
		public void add(int c) {
			this.count.addAndGet(c);
		}
		
		public QueryFacet(String id, Query query, AtomicLong count) {
			this.id = id;
			this.query = query;
			this.count = count;
		}

		public QueryFacet(Element root) throws Exception {
			XMLUtil.reflectToObject(this, root);
		}

		public Element toElement() throws Exception {
			return XMLUtil.reflectToElement("queryfacet", this);
		}
	}

	public static class FieldFacet {
		public String field;
		public Map<String, AtomicLong> termCountMap = new HashMap<String, AtomicLong>();
		ReentrantLock lock = new ReentrantLock();

		public FieldFacet() {
		}

		public FieldFacet(String field) {
			this.field = field;
		}

		public void add(String termText, int count) {
			AtomicLong total = termCountMap.get(termText);
			if (total == null) {
				lock.lock();
				try {
					if (!termCountMap.containsKey(termText)) {
						total = new AtomicLong(0);
						termCountMap.put(termText, total);
					} else {
						total = termCountMap.get(termText);
					}
				} finally {
          lock.unlock();
				}
			}
			total.addAndGet((int) count);
		}

		public FieldFacet(Element root) throws Exception {
			XMLUtil.reflectToObject(this, root);
		}

		public Element toElement(IndexSchema indexSchema) throws Exception {
			Element root = new Element("fieldfacet");
			XMLUtil.setAttribute("field", field, root);
			for (Map.Entry<String, AtomicLong> entry : termCountMap.entrySet()) {
				Element element = new Element("count");
				String readable = ClusterUtil.indexedToReadable(field, entry.getKey(), indexSchema);
				XMLUtil.setAttribute("text", readable, element);
				XMLUtil.setAttribute("count", entry.getValue().toString(), element);
				root.addContent(element);
			}
			return root;
		}
	}
}
